package com.alogic.cert;

import com.anysoft.util.BaseException;
import com.anysoft.util.IOTools;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.openssl.*;
import org.bouncycastle.openssl.PKCS8Generator;

import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.jcajce.JceInputDecryptorProviderBuilder;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;


/**
 * Tools
 *
 * @since 1.6.13.40 [20210306 duanyy] <br>
 */
public class CertTools {
    /**
     * a logger of slf4j
     */
    protected static final Logger LOG = LoggerFactory.getLogger(CertTools.class);

    /**
     * 从Pem字符串中加载证书
     * @param pemContent pem形式的字符串
     * @return 证书对象
     */
    public static X509Certificate loadX509Certificate(String pemContent){
        PEMParser reader= new PEMParser(new StringReader(pemContent));
        try {
            Object pemObject = reader.readObject();
            if (pemObject != null && pemObject instanceof X509CertificateHolder){
                X509CertificateHolder holder = (X509CertificateHolder)pemObject;
                return new JcaX509CertificateConverter().getCertificate(holder);
            }
        } catch (Exception e) {
            throw new BaseException("core.cert",e.getMessage());
        } finally {
            IOTools.close(reader);
        }
        return null;
    }

    /**
     * 从pem字符串中加载私钥
     * @param pemContent pem形式的字符串
     * @param password 私钥的密码
     * @return 私钥对象
     */
    public static PrivateKey loadPrivateKey(String pemContent,String password){
        PEMParser reader= new PEMParser(new StringReader(pemContent));
        try {
            Object pemObject = reader.readObject();
            if (pemObject != null){
                JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
                KeyPair kp;
                if (pemObject instanceof PEMEncryptedKeyPair) {
                    if (StringUtils.isEmpty(password)){
                        throw new BaseException("core.cert","Private key password is null");
                    }else {
                        PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) pemObject;
                        PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
                        kp = converter.getKeyPair(ckp.decryptKeyPair(decProv));
                        return kp.getPrivate();
                    }
                } else {
                    if (pemObject instanceof PEMKeyPair) {
                        PEMKeyPair ukp = (PEMKeyPair) pemObject;
                        kp = converter.getKeyPair(ukp);
                        return kp.getPrivate();
                    }else{
                        if (pemObject instanceof PrivateKeyInfo){
                            PrivateKeyInfo keyInfo = (PrivateKeyInfo)pemObject;
                            return converter.getPrivateKey(keyInfo);
                        }else{
                            if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo){
                                if (StringUtils.isEmpty(password)){
                                    throw new BaseException("core.cert","Private key password is null");
                                }else {
                                    PKCS8EncryptedPrivateKeyInfo privateKeyInfo = (PKCS8EncryptedPrivateKeyInfo) pemObject;
                                    InputDecryptorProvider decProv = new JceInputDecryptorProviderBuilder().build(password.getBytes());
                                    return converter.getPrivateKey(privateKeyInfo.decryptPrivateKeyInfo(decProv));
                                }
                            }
                        }
                    }
                }
            }
        } catch (PEMException e) {
            throw new BaseException("core.cert",e.getMessage());
        } catch (IOException e) {
            throw new BaseException("core.cert",e.getMessage());
        } catch (PKCSException e) {
            throw new BaseException("core.cert",e.getMessage());
        } finally {
            IOTools.close(reader);
        }
        return null;
    }
}
